﻿using Avalon.Core.Data;
using Avalon.Core.Providers;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.WebPages;

namespace Avalon.Core.MVC {
    public class AvalonCompiledView : IView {
        internal IViewPageActivator ViewPageActivator;
        private ControllerContext _controllerContext;

        public AvalonCompiledView(ControllerContext controllerContext, string viewPath)
            : this(controllerContext, viewPath, null) {
        }

        protected AvalonCompiledView(ControllerContext controllerContext, string viewPath, IViewPageActivator viewPageActivator)
            : this(controllerContext, viewPath, viewPageActivator, null) {
        }

        protected AvalonCompiledView(ControllerContext controllerContext, string viewPath, IViewPageActivator viewPageActivator, IDependencyResolver dependencyResolver) {
            if (controllerContext == null) {
                throw new ArgumentNullException("controllerContext");
            }
            _controllerContext = controllerContext;

            IRendererDescriptor renderDescriptor = ContextProvider.ControllerDescriptor.RendererDescriptor;
            if (renderDescriptor != null &&
                !string.IsNullOrWhiteSpace(renderDescriptor.ViewName) &&
                !string.IsNullOrWhiteSpace(renderDescriptor.FolderName)) {
                ViewPath = string.Format("~/{0}/{1}.cshtml", renderDescriptor.ViewName, renderDescriptor.FolderName);
            }
            else {
                ViewPath = viewPath;
            }
            ViewPageActivator = null;
        }

        public string ViewPath { get; protected set; }

        public void Render(ViewContext viewContext, TextWriter writer) {
            object instance = new _viewPage(viewContext);
            RenderView(viewContext, writer, instance);
        }

        protected void RenderView(ViewContext viewContext, TextWriter writer, object instance) {
            //set parent data
            viewContext.ViewBag.parentId = HttpContext.Current.Request.QueryString["parentId"];
            viewContext.ViewBag.parentName = HttpContext.Current.Request.QueryString["parentName"];

            // Initialize the View Page
            _viewPage webViewPage = (_viewPage)instance;
            webViewPage.Layout = "~/Views/Shared/_Layout.cshtml";
            webViewPage.VirtualPath = "~";
            if (ContextProvider.RendererType == RendererType.TypedRenderer) {
                webViewPage.Renderer = ContextProvider.ControllerDescriptor.RendererDescriptor.ViewRenderer;
            }
            else {
                webViewPage.Renderer = ProviderContainer.Current.RendererProvider.GetViewRenderer().ViewRenderer;
            }
            webViewPage.Html = new HtmlHelper<object>(viewContext, new GenericViewData(viewContext.ViewData));

            //set the model metadata
            if (webViewPage.ViewContext.ViewData.Model is IEntity) {
                webViewPage.ViewContext.ViewData.ModelMetadata = ModelMetadataProviders.Current.GetMetadataForType(null, viewContext.ViewData.Model.GetType());
            }
            else if (webViewPage.ViewContext.ViewData.Model is IEnumerable<IEntity>) {
                webViewPage.ViewContext.ViewData.ModelMetadata = ModelMetadataProviders.Current.GetMetadataForType(
                    null,
                    webViewPage.ViewContext.ViewData.Model.GetType().GetGenericArguments().First()
                );
            }

            // Set the page context and Execute the Hierarchy to render the rendered view in the _Layout
            var pageContext = new WebPageContext(viewContext.HttpContext, null, null);
            var startPage = StartPage.GetStartPage(webViewPage, "~/Views/_ViewStart.cshtml", new List<string>());
            webViewPage.ExecutePageHierarchy(pageContext, writer, startPage);
        }

        //A private class implementing IVIewDataContainer. This class has no specific meaning except to help
        //build the HtmlHelper constructor.
        private class GenericViewData : IViewDataContainer {
            public ViewDataDictionary ViewData { get; set; }

            public GenericViewData(ViewDataDictionary viewData) {
                this.ViewData = viewData;
            }
        }
    }

    public class _viewPage : WebViewPage<object> {
        public IViewRenderer Renderer { get; set; }
        public _viewPage(ViewContext context) {
            ViewContext = context;
        }

        public override void Execute() {
            HtmlString htmlString = this.Renderer.ViewRenderHelper.Render(this.Html);
            this.GetOutputWriter().Write(htmlString.ToString());
        }
    }


}
